#ifndef __VECTOR__HPP__
#define __VECTOR__HPP__
#include <cmath>
#include <iostream>

using namespace std;

/*
	Classe vecteur avec template :
		exemple de déclaration :
			vector<int> v; pour un vecteur d'int
*/

template <class T> class vector{
	public:
		T x, y, z;
	public:
		vector();					//x,y,z à 0
		vector(T x, T y);			//z à 0
		vector(T x, T y, T z);
		vector(const vector& v);
		void normalize();
		T length();
		T dot(const vector& v);				//Dot product
		vector operator+ (const vector& v);
		void operator+= (const vector& v);
		vector operator- (const vector& v);
		void operator-= (const vector& v);
		vector operator^ (const vector& v);	//inplace multiplication
		vector operator* (const vector& v);	//Cross product
		void operator*= (const vector& v);	//Cross product
		vector operator* (const T& d);
		vector operator/ (const T& d);
		void operator*= (const T& d);
		void print();
};

template <class T>
vector<T>::vector(){
	this->x = this->y = this->z = T(0);
}

template <class T>
vector<T>::vector(T x, T y){
	this->x = x;
	this->y = y;
	this->z = T(0);
}

template <class T>
vector<T>::vector(T x, T y, T z){
	this->x = x;
	this->y = y;
	this->z = z;
}

template <class T>
vector<T>::vector(const vector<T>& v){
	this->x = v.x;
	this->y = v.y;
	this->z = v.z;
}

template <class T>
void vector<T>::normalize() {
	T l = length();
	x /= l;
	y /= l;
	z /= l;
}

template <class T>
T vector<T>::length() {
	return sqrt(x*x+y*y+z*z);
}

template <class T>
T vector<T>::dot(const vector<T>& v) {
	return x * v.x + y * v.y + z * v.z;
}

template <class T>
vector<T> vector<T>::operator+(const vector<T>& v){
	vector<T> res;
	res.x = x + v.x;
	res.y = y + v.y;
	res.z = z + v.z;
	return res;
}

template <class T>
void vector<T>::operator+=(const vector<T>& v){
	x = x + v.x;
	y = y + v.y;
	z = z + v.z;
}

template <class T>
vector<T> vector<T>::operator-(const vector<T>& v){
	vector<T> res;
	res.x = x - v.x;
	res.y = y - v.y;
	res.z = z - v.z;
	return res;
}

template <class T>
void vector<T>::operator-=(const vector<T>& v){
	x = x - v.x;
	y = y - v.y;
	z = z - v.z;
}

template <class T>
vector<T> vector<T>::operator^(const vector<T>& v){
	vector<T> res;
	res.x = x * v.x;
	res.y = y * v.y;
	res.z = z * v.z;
	return res;
}

template <class T>
vector<T> vector<T>::operator*(const vector<T>& v){
	vector<T> res;
	res.x = y * v.z - z * v.y;
	res.y = z * v.x - x * v.z;
	res.z = x * v.y - y * v.x;
	return res;
}

template <class T>
void vector<T>::operator*=(const vector<T>& v){
	x = y * v.z - z * v.y;
	y = z * v.x - x * v.z;
	z = x * v.y - y * v.x;
}

template <class T>
vector<T> vector<T>::operator*(const T& d){
	vector<T> res;
	res.x = x * d;
	res.y = y * d;
	res.z = z * d;
	return res;
}

template <class T>
void vector<T>::operator*=(const T& d){
	x = x * d;
	y = y * d;
	z = z * d;
}

template <class T>
vector<T> vector<T>::operator/(const T& d){
	vector<T> res;
	res.x = x / d;
	res.y = y / d;
	res.z = z / d;
	return res;
}

template <class T>
void vector<T>::print(){
	cout<<"x: "<<x<<" y:"<<y<<" z:"<<z<<endl;
}

#endif
